// programa client cujo objetivo e solicitar um arquivo ao servidor e gavar-lo em disco local
//@param host_do_servidor porto_servidor nome_arquivo tam_buffer
//@host_do_servidor = nome do servidor ex(localhost,127.0.0.1)
//@porto_servidor = porto em que o servidor esta "bind"
//@nome_arquivo = nome do arquivo a ser solicitado
//@tam_buffer = tamanho do buffer a ser utilizado

//bibliotecas utilizadas
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h> 

//funcao de auxilio para informar erros e abortar
void error(char *msg)
{
    printf("\n%s\n", msg);
    exit(0);
}
//funcao de auxilio para informar como usar o programa
void usage()
{
	printf("Usage: \n ./client host_server port nome_arquivo tam_buffer\n"); 
	printf("\t host_server: \t  Nome do servidor\n"); 
	printf("\t port: \t\t  Porto do servidor\n"); 
	printf("\t nome_arquivo:\t  Arquivo a ser requerido\n"); 
	printf("\t tam_buffer:\t  Tamanho do buffer a ser utilizado\n"); 
} 

int main(int argc, char *argv[])
{
	//verifica numero de argumentos
	if (argc != 5) {
		usage();	
		error("Numero de argumentos invalido");	 
	}
   
	//declaracoes iniciais 
	int sockfd, port=atoi(argv[2]), n, totalBytes=0, totalMsg=0;
	char *arquivo = argv[3];
	struct sockaddr_in serv_addr;
	struct hostent *server;
	char buffer[atoi(argv[4])];
	struct timeval time1, time2;
	FILE *file;
	int sec, msec; 
	float kbps;
    	
	//inicia a contagem do tempo
	gettimeofday(&time1,NULL);


	//cria o novo socket TCP
	sockfd = socket(AF_INET, SOCK_STREAM, 0);
	if (sockfd < 0){ 
        	error("ERROR abrindo o socket");
	}

	//Pega o endereço do server
	server = gethostbyname(argv[1]);
	
	//verifica se foi possivel encontrar o endereco do host
	if (server == NULL) {
		error("Host nao encontrado");
	}

	//define o address family do sockaddr_in 
	serv_addr.sin_family= AF_INET;

	//define o porto a ser utilizado, lembrando de converter antes para network byte order
	serv_addr.sin_port=htons(port);

	//copia o endereco ip do servidor pego pelo gethostbyname, para o serv_addr 
	bcopy((char *) server->h_addr, (char *) &serv_addr.sin_addr.s_addr, server->h_length);
		
	//faz a abertura ativa
	if( connect(sockfd,(const struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0){
		//imprime as informacoes da conexao
		printf("Server end: \t %s\n", server->h_name);
		printf("Server port:\t %d\n", port);
		error("Erro na conexao com o servidor"); 
	}

	//abre o arquivo para ser escrito
	file = fopen(arquivo,"w+");
	
	if ( file == NULL ){
		error("Problema ao abrir o arquivo para escrita");
	}
	

	//incrementa o nome do arquivo com 0 no final
	strncat(arquivo,"0",1);

	//tenta enviar a solicitacao do arquivo
	n = write(sockfd,arquivo,strlen(arquivo));
	if ( n < 0 ){
		error("Falha na escrita para o socket");
	} 


	//começa a receber o arquivo
	n=recv(sockfd,buffer,sizeof(buffer), 0);
	while ( n > 0 ){
		fwrite(buffer,1,n,file);
		totalBytes+=n;
		totalMsg++;
		n=recv(sockfd,buffer,sizeof(buffer), 0);
	}	

	//fecha o arquivo 
	fclose(file);

	//fecha a conexao, para de receber e transmitir
	shutdown(sockfd,2);
	
	//termina a contagem do tempo
	gettimeofday(&time2,NULL);

	//calcula as medidas com base no tempo gasto
	sec = (int)  (time2.tv_sec - time1.tv_sec);
	msec = (int ) (time2.tv_usec - time1.tv_usec);
	kbps = (totalBytes* 8.0 /( (int)sec + (float) ( msec /1000000.0) )) /1024.0;

	//imprime os resultados
	printf("Iteracoes no recv(): %d\n", totalMsg);
	printf("Buffer = \%5u byte(s), \%10.2f kbps (\%u bytes em \%3u.\%06u s)\n", totalBytes, kbps, totalBytes,(unsigned int) sec, (unsigned int) msec); 

}
